/**
 * Copyright (C) 2015 Eshore Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.eshore.thrpc.pool;

import org.apache.commons.pool2.KeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.thrift.TServiceClient;
import org.apache.thrift.TServiceClientFactory;
import org.apache.thrift.transport.TTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eshore.thrpc.RpcException;
import com.eshore.thrpc.client.thrift.ThriftBlockingClient;
import com.eshore.thrpc.client.thrift.ThriftNonBlockingClient;
import com.eshore.thrpc.common.ServerNode;

/**
 * TserviceClient链接池工厂(非单例，可重载，建议使用时单例)
 * <p>
 * 
 * @author : zhouzhixiang
 * @date : 2016-11-12
 */
public class TServiceClientPoolFactory
        implements
            KeyedPooledObjectFactory<ServerNode, TServiceClient> {

    /** LOGGER */
    private final Logger LOGGER = LoggerFactory.getLogger(getClass());

    /** {@link TServiceClientFactory }<{@link TServiceClient}> */
    private final TServiceClientFactory<TServiceClient> clientFactory;

    /** 超时时间 */
    private final int timeout;

    /**
     * @param clientFactory
     * @param timeout
     */
    public TServiceClientPoolFactory(TServiceClientFactory<TServiceClient> clientFactory,
            int timeout) {
        this.clientFactory = clientFactory;
        this.timeout = timeout;
    }

    /**
     * 
     * 构建客户端
     * 
     * @author zhouzhixiang
     * @param key
     * @return
     * @throws Exception
     */
    public TServiceClient createClient(ServerNode key) throws Exception {
        if (key != null) {
            TServiceClient client = null;
            if (key.isNonBlock()) {
                client =
                        new ThriftNonBlockingClient(clientFactory).getClient(key.getIp(),
                                key.getPort(), timeout);
                LOGGER.info("client:{} connecting to the server {} [{}:{}] using a nonblocking method",
                        client.hashCode(), key.getName(), key.getIp(), key.getPort());
            } else {
                client =
                        new ThriftBlockingClient(clientFactory).getClient(key.getIp(),
                                key.getPort(), timeout);
                LOGGER.info(
                        "client:{} connecting to the server {} [{}:{}] using a blocking method",
                        client.hashCode(), key.getName(), key.getIp(), key.getPort());
            }
            return client;
        }
        LOGGER.error("Not find a vilid server!");
        throw new RpcException("Not find a vilid server!");
    }

    /**
     * 从池里获取TServiceClient对象
     * 
     * 
     * @author zhouzhixiang
     * @param key
     * @return
     * @throws Exception
     */
    @Override
    public PooledObject<TServiceClient> makeObject(ServerNode key) throws Exception {
        return new DefaultPooledObject<TServiceClient>(createClient(key));
    }

    /**
     * 关闭客户端
     * 
     * 
     * @author zhouzhixiang
     * @param key
     * @param p
     * @throws Exception
     */
    @Override
    public void destroyObject(ServerNode key, PooledObject<TServiceClient> p) throws Exception {
        TTransport tp = p.getObject().getInputProtocol().getTransport();
        tp.close();
        p.markAbandoned();
    }

    /**
     * 
     * 校验
     * 
     * @author zhouzhixiang
     * @param key
     * @param p
     * @return
     */
    @Override
    public boolean validateObject(ServerNode key, PooledObject<TServiceClient> p) {
        return true;
    }


    /**
     * 
     * 激活客户端连接
     * 
     * @author zhouzhixiang
     * @param key
     * @param pooledObject
     * @throws Exception
     */
    @Override
    public void activateObject(ServerNode key, PooledObject<TServiceClient> pooledObject)
            throws Exception {
        if (!pooledObject.getObject().getInputProtocol().getTransport().isOpen()) {
            pooledObject.getObject().getInputProtocol().getTransport().open();
        }
    }


    /**
     * 
     * 钝化什么都不做
     * 
     * @author zhouzhixiang
     * @param key
     * @param p
     * @throws Exception
     */
    @Override
    public void passivateObject(ServerNode key, PooledObject<TServiceClient> pooledObject)
            throws Exception {}


}
